﻿using System;
using System.Collections.Generic;
//using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using System.Windows.Forms;

namespace Server
{
    public class ServerProgram
    {
        #region -  SOCKET  -
        private TcpListener server = null;
        private ClientProgram c = null;
        private TcpClient client = null;
        private ClientProgram clientProgram = null;
        public List<ClientProgram> listClients = null;
        //private DataPackage package = null;
        public StringBuilder sb = null;
        #endregion

        #region -  THREADS  -
        private Thread tMainThread = null;
        private Thread tShowMessageBox = null;
        private Thread tShowProgessBar = null;
        private Thread tShowViewDesktopClient = null;
        private Thread tViewListProcesses = null;

        #endregion

        #region -  EVENTS  -
        public event UnCheckUSBDetectEventhHandler OnUnCheckUSBDetect = null;
        public event ClientExitEventHandler OnClientExit = null;
        public event NewClientEventHandler OnNewClient = null;
        #endregion

        #region -  CONTRUCTOR  -
        public ServerProgram()
        {
            try
            {
                this.server = new TcpListener(IPAddress.Any, 5000);
                this.server.Start();
                this.listClients = new List<ClientProgram>();
                this.sb = new StringBuilder();
                //Create mainThread instance and Start thread
                this.tMainThread = new Thread(new ThreadStart(StartServer));
                this.tMainThread.Priority = ThreadPriority.Normal;
                this.tMainThread.Start();
            }
            catch
            { }
        }
        #endregion

        #region -  START SERVER  -
        public void StartServer()
        {
            try
            {
                while (true)
                {
                    if (!this.server.Pending())
                    {
                        Thread.Sleep(1000);
                    }
                    //Wait Client Connect
                    this.client = this.server.AcceptTcpClient();
                    this.clientProgram = new ClientProgram(this.client);

                    //Add Client to List
                    this.listClients.Add(this.clientProgram);

                    //Client events
                    this.clientProgram.OnSendFilename += new SendFilenameEventHandler(clientProgram_OnSendFilename);
                    this.clientProgram.OnSendFilePercent += new SendFilePercentEventHandler(clientProgram_OnSendFilePercent);
                    this.clientProgram.OnReceiveMessage += new ReceiveMessageEventHandler(clientProgram_OnReceiveMessage);
                    this.clientProgram.OnViewDesktopClient += new ViewDesktopClientEventHandler(clientProgram_OnViewDesktopClient);
                    this.clientProgram.OnReceiveFilename += new ReceiveFilenameEventHandler(clientProgram_OnReceiveFilename);
                    this.clientProgram.OnReceiveFilePercent += new ReceiveFilePercentEventHandler(clientProgram_OnReceiveFilePercent);
                    this.clientProgram.OnUSBDetected += new USBDetectedEventHandler(clientProgram_OnUSBDetected);
                    this.clientProgram.OnGetListProcesses += new GetListProcessesEventHandler(clientProgram_OnGetListProcesses);
                    this.clientProgram.OnAttendenceCheck += new AttendenceCheckEventHandler(clientProgram_OnAttendenceCheck);
                    this.clientProgram.OnClientExit += new ClientExitEventHandler(clientProgram_OnClientExit);

                    if (this.OnNewClient != null)
                    {
                        this.OnNewClient(this, new NewClientEventArgs(this.clientProgram.GetIPAddress()));
                    }
                }
            }
            catch
            {
            }
        }

        void clientProgram_OnClientExit(object sender, ClientExitEventArgs e)
        {
            if (this.OnClientExit != null)
            {
                listClients.RemoveAll(delegate(ClientProgram c)
                {
                    return c.GetIPAddress().Equals(e.IpAddress);
                });
                this.OnClientExit(this, new ClientExitEventArgs(e.IpAddress));
            }
        }
        #endregion

        #region -  ATTENDENCE CHECK  -
        void clientProgram_OnAttendenceCheck(object sender, AttendenceCheckEventArgs e)
        {
            this.sb.AppendLine(e.Data);
        }
        #endregion

        #region -  GET LIST PROCESSES  -
        void clientProgram_OnGetListProcesses(object sender, GetListProcessesEventArgs e)
        {
            this.c = (ClientProgram)sender;
            string[] listProcesses = e.ListProcesses;
            for (int i = 0; i < listProcesses.Length - 1; i += 3)
            {
                this.c.SetListProcessesData(listProcesses[i], listProcesses[i + 1],
                    Format.NumberFormat(listProcesses[i + 2]) +"K");
                
            }
            this.c.SetReload();
            this.tViewListProcesses = new Thread(new ParameterizedThreadStart(ShowListProcesses));
            this.tViewListProcesses.Priority = ThreadPriority.Lowest;
            this.tViewListProcesses.Start(this.c);
        }

        private void ShowListProcesses(object sender)
        {
            try
            {
                this.c = (ClientProgram)sender;
                this.c.SetViewListProcesses();
                this.c.ShowListProcesses();
                if (this.tViewListProcesses != null)
                {
                    this.tViewListProcesses.Abort();
                }
            }
            catch { }
        }
        #endregion

        #region -  USB DETECTED  -
        void clientProgram_OnUSBDetected(object sender, USBDetectedEventArgs e)
        {
            this.c = (ClientProgram)sender;
            switch (MessageBox.Show("Phát hiện máy trạm " + c.GetIPAddress() + " đang sử dụng USB.\nBạn có muốn đóng hộp thoại này không?", "Cảnh báo",
                 MessageBoxButtons.YesNo, MessageBoxIcon.Warning))
            { 
                case DialogResult.Yes:
                    this.c.sendQueue.Enqueue(new DataPackage(Command.USBDectect, null, 0));
                    if (this.OnUnCheckUSBDetect != null)
                    {
                        this.OnUnCheckUSBDetect(this, new UnCheckUSBDetectEventArgs());
                    }
                    break;
                case DialogResult.No:
                    this.c.sendQueue.Enqueue(new DataPackage(Command.USBDectect, null, 1));
                    break;
            }
        }
        #endregion

        #region -  RECEIVE FILE  -
        void clientProgram_OnReceiveFilePercent(object sender, PercentEventArgs e)
        {
            this.c = (ClientProgram)sender;
            this.c.SetProgressBarValue(e.Percent);
            this.c.SetProgressBarTitle("Receiving ... " + e.Percent + " %");
        }

        void clientProgram_OnReceiveFilename(object sender, FilenameEventArgs e)
        {
            try
            {
                this.c = (ClientProgram)sender;
                this.c.SetProgressBar();
                this.c.SetProgressBarMessage("Nhận tệp tin '" + e.Filename + "' từ " + c.GetIPAddress());
                this.tShowProgessBar = new Thread(new ParameterizedThreadStart(ShowProgressBar));
                this.tShowProgessBar.Start(this.c);
            }
            catch
            { }
        }
        #endregion

        #region -  VIEW CLIENT DESKTOP  -
        void clientProgram_OnViewDesktopClient(object sender, ViewDesktopClientEventsArgs e)
        {
            this.c = (ClientProgram)sender;
            this.c.SetViewDesktopClient();
            this.c.SetViewDesktopClientData(e.Img);
            this.tShowViewDesktopClient = new Thread(new ParameterizedThreadStart(ShowViewDesktopClient));
            this.tShowViewDesktopClient.Priority = ThreadPriority.Lowest;
            this.tShowViewDesktopClient.Start(this.c);
        }

        private void ShowViewDesktopClient(object obj)
        {
            this.c = (ClientProgram)obj;
            this.c.ShowViewDesktopClient();
            if (this.tShowViewDesktopClient != null)
            {
                this.tShowViewDesktopClient.Abort();
            }
        }
        #endregion

        #region -  RECEIVE MESSAGE  -
        void clientProgram_OnReceiveMessage(object sender, MessageEventArgs e)
        {
            this.c = (ClientProgram)sender;
            this.c.SetMessageBox(e.IpAddress);
            this.c.SetMessage(e.Message);
            this.tShowMessageBox = new Thread(new ParameterizedThreadStart(ShowMessageBox));
            this.tShowMessageBox.Priority = ThreadPriority.Lowest;
            this.tShowMessageBox.Start(this.c);
        }

        private void ShowMessageBox(object obj)
        {
            this.c = (ClientProgram)obj;
            this.c.ShowMessageBox();
            if (this.tShowMessageBox != null)
            {
                this.tShowMessageBox.Abort();
            }
        }
        #endregion

        #region -  SENDING FILE AND SHOW PROGRESS BAR  -
        void clientProgram_OnSendFilePercent(object sender, PercentEventArgs e)
        {
            this.c = (ClientProgram)sender;
            this.c.SetProgressBarValue(e.Percent);
            this.c.SetProgressBarTitle("Đang gửi ... " + e.Percent + " %");
        }

        void clientProgram_OnSendFilename(object sender, FilenameEventArgs e)
        {
            try
            {
                this.c = (ClientProgram)sender;
                this.c.SetProgressBar();
                this.c.SetProgressBarMessage("Đang gửi tệp tin '" + e.Filename + "' đến " + c.GetIPAddress());
                this.tShowProgessBar = new Thread(new ParameterizedThreadStart(ShowProgressBar));
                this.tShowProgessBar.Priority = ThreadPriority.Lowest;
                this.tShowProgessBar.Start(c);
            }
            catch
            { }
        }

        private void ShowProgressBar(object obj)
        {
            this.c = (ClientProgram)obj;
            this.c.ShowProgressBar();
            if (this.tShowProgessBar != null)
            {
                this.tShowProgessBar.Abort();
            }
        }
        #endregion
                
        #region -  STOP SERVER  -
        public void StopServer()
        {
            try
            {
                this.server.Stop();
                foreach (ClientProgram c in this.listClients)
                {
                    c.StopClient1();
                }
                this.tMainThread.Abort();
                if (this.tShowMessageBox != null)
                {
                    this.tShowMessageBox.Abort();
                }
                if (this.tShowProgessBar != null)
                {
                    this.tShowProgessBar.Abort();
                }
                if (this.tShowViewDesktopClient != null)
                {
                    this.tShowViewDesktopClient.Abort();
                }
                if (this.tViewListProcesses != null)
                {
                    this.tViewListProcesses.Abort();
                }
            }
            catch
            { }
        }
        #endregion

        #region -  FIND CLIENT  -
        public ClientProgram FindClient(string ipAddress)
        {
            this.c = this.listClients.Find(delegate(ClientProgram cp)
            {
                return cp.GetIPAddress().Equals(ipAddress);
            });
            return this.c;
        }
        #endregion

        #region -  SET SEND QUEUE  -
        public void SetSendQueue(ClientProgram c, object obj)
        {
            c.sendQueue.Enqueue(obj);
        }
        #endregion

        #region -  SET SAVE FILE TO DIRECTORY  -
        public void SetSaveFileToDirectory(string path)
        {
            foreach (ClientProgram c in listClients)
            {
                c.SetFilePath(path);
            }
        }
        #endregion
    }
}
